#-*- coding:utf-8 -*-
import logging
import os
import datetime
import time_ext_
import traceback
from logging.handlers import TimedRotatingFileHandler
from concurrent_log_handler import ConcurrentRotatingFileHandler
# from logging.handlers import RotatingFileHandler
from PyQt5.QtCore import QObject, pyqtSignal
import win32api
import win32con
# from functools import wraps
LOG_INFO = {
    'level': 10,
    # 是否存储日志
    'saveLog': 'Y',
    # 存储日志路径
    'logPath': './log',
    # 日志文件切割周期 D,H,M,S,天，时，分，秒
    'time': 'H:1',
    # 存储日志个数
    'saveNumber': 168,
    # 日志大小
    'logSize': 5

}


class QtHandler(logging.Handler):

    def __init__(self):
        logging.Handler.__init__(self)

    def emit(self, record):
        record = self.format(record)
        XStream.stdout().write("{}".format(record))


class XStream(QObject):
    _stdout = None
    _stderr = None
    messageWritten = pyqtSignal(str)

    def flush(self):
        pass

    def fileno(self):
        return -1

    def write(self, msg):
        if (not self.signalsBlocked()):
            self.messageWritten.emit(msg)

    @staticmethod
    def stdout():
        if (not XStream._stdout):
            XStream._stdout = XStream()
        return XStream._stdout

    @staticmethod
    def stderr():
        if (not XStream._stderr):
            XStream._stderr = XStream()
        return XStream._stderr


class Logger(object):

    def __init__(self, config=LOG_INFO, name="main", short=False):
        """[summary]

        [标准日志模块封装]

        参数:
            config: [日志配置参数dict类型] (default: {level:等级0-50/步进10，saveLog:是否保存日志，Y/N,logPath:日志存储路径，time:日志切割周期 D/H/M/S:N,如每小时1个=H:1,saveNumber:存储日志最多数量 })
        """
        self.logger = logging.getLogger(name)
        # 日志总等级
        self.level = int(config['level'])
        self.logger.setLevel(self.level)
        # 定义handler的输出格式并将格式应用到handler
        self.short = short
        self.formatter = logging.Formatter(
            "{}\n * %(asctime)s %(levelno)s %(message)s\n{}\n".format('*' * 80, '*' * 80))
        self.setConsoleLog()
        self.setSaveLog(config)
        self.setQtUiLog()
        self.debug = self.logger.debug
        self.info = self.logger.info
        self.warning = self.logger.warning
        self.error = self.logger.error
        self.critical = self.logger.critical
        self.exc = self.logger.exception
        self.log = self.logger.log

    # 设置日志输出
    def setQtUiLog(self):
        qtUi_handler = QtHandler()
        qtUi_handler.setLevel(self.level+10)
        if self.short:
            qtUi_handler.setFormatter(logging.Formatter(
                "%(asctime)s %(levelno)s %(message)s"))
        else:
            qtUi_handler.setFormatter(logging.Formatter(
                "{}<br> * %(asctime)s %(levelno)s %(message)s<br>{}<br><br>".format('*' * 80, '*' * 80)))

        self.logger.addHandler(qtUi_handler)
    # 设置日志输出控制台

    def setConsoleLog(self):
        # 控制台日志
        console_handler = logging.StreamHandler()
        # 日志等级
        console_handler.setLevel(self.level)
        console_handler.setFormatter(self.formatter)
        self.logger.addHandler(console_handler)
    # 设置日志存储到文件

    def setSaveLog(self, config):
        if config['saveLog'] == 'Y':
            logpath = os.path.abspath(config['logPath'])
            cycle = config['time'].split(":")
            try:
                os.mkdir(logpath)
                print(" * 日志文件夹创建成功")
            except:
                #print(" * 日志文件夹已存在")
                pass
            if config.get('logSize'):
                log_file_handler = ConcurrentRotatingFileHandler(
                    logpath + "/log", "a", int(config['logSize']) * 1024 * 1024, int(config['saveNumber']))
            else:
                log_file_handler = TimedRotatingFileHandler(filename=logpath + "/log", when="%s" % cycle[
                                                            0], interval=int("%s" % cycle[1]), backupCount=int(config['saveNumber']))
                if cycle[0] == "D":
                    log_file_handler.suffix = "%Y-%m-%d.log"
                elif cycle[0] == "H":
                    log_file_handler.suffix = "%Y-%m-%d_%H.log"
                elif cycle[0] == "M":
                    log_file_handler.suffix = "%Y-%m-%d_%H-%M.log"
                elif cycle[0] == "S":
                    log_file_handler.suffix = "%Y-%m-%d_%H-%M-%S.log"
            log_file_handler.setFormatter(self.formatter)
            self.logger.addHandler(log_file_handler)

    def write(self, message='', level=10):
        message = str(message)
        # 输出日志
        if level <= 10:
            self.logger.debug(message)
        elif level <= 20:
            self.logger.info(message)
        elif level <= 30:
            self.logger.warning(message)
        elif level <= 40:
            self.logger.error(message)
        elif level > 40:
            self.logger.critical(message)
# logger=Logger(name="main.logger")


def warpper_log(func):
    def wrapper(self, *args, **kwargs):
        logger = Logger(name="main.{}".format(func.__name__))
        try:
            func.log = logger
            return func(self, *args, **kwargs)
        except Exception as e:
            logger.debug("对象：{},异常：{}".format(func.__name__, e))
            time_ext_.sleep(3)
            return False
    return wrapper


def wrapper_error(origin_func):
    def wrapper(self, *args, **kwargs):
        try:
            u = origin_func(self, *args, **kwargs)
            return u
        except Exception as e:
            return logger.debug("对象：{},异常：{}".format(origin_func.__name__, e))
    return wrapper
# 全局捕获异常存储日志


def error(exc_type, exc_value, exc_tb):
    """摘要

    功能描述：全局异常捕获存储

    参数:
        exc_type: [描述: 异常类型]
        exc_value: [描述: 异常对象]
        exc_tb: [描述: 异常的traceback]
    """

    error_log_path = './log/'
    try:
        os.mkdir(os.path.abspath(error_log_path))
        print(" * 日志文件夹创建成功")
    except:
        # print(" * 日志文件夹已存在")
        pass
    error_file_name = '{}{}{}'.format(
        'ERROR_', datetime.datetime.now().date(), '.log')
    error_file_path = os.path.join(error_log_path, error_file_name)
    with open(error_file_path, mode='a+') as file:
        errinfo = exc_value
        errline = None
        # errvalue=None
        i = 1
        while exc_tb:
            msg = " * {} 第{}层堆栈信息".format(datetime.datetime.now(), i)
            print(msg)
            file.writelines(msg + '\n')
            tracebackCode = exc_tb.tb_frame.f_code
            msg = " * {} 引起异常文件= {}".format(datetime.datetime.now(),
                                            tracebackCode.co_filename)
            print(msg)
            file.writelines(msg + '\n')
            msg = " * {} 函数或者模块名= {}".format(datetime.datetime.now(),
                                             tracebackCode.co_name)
            print(msg)
            file.writelines(msg + '\n')
            msg = " * {} 异常行= {}".format(datetime.datetime.now(),
                                         exc_tb.tb_lineno)

            errline = exc_tb.tb_lineno
            print(msg)
            file.writelines(msg + '\n')
            # errvalue=exc_tb.tb_frame.f_locals
            exc_tb = exc_tb.tb_next
            i += 1
        msg = (' * {} 异常提示= {}'.format(datetime.datetime.now(), errinfo))
        win32api.MessageBox(0, msg, "错误", win32con.MB_OK)
        print(msg)
        file.writelines(msg + '\n')

if __name__ == '__main__':
    Log = Logger()
    Log.write('chat xxxx', level=10)


# 模块级函数
#
# logging.getLogger([name]):返回一个logger对象，如果没有指定名字将返回root logger
# logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()：设定root logger的日志级别
# logging.basicConfig():用默认Formatter为日志系统建立一个StreamHandler，设置基础配置并加到root logger中
#
# Loggers
#
# Logger.setLevel(lel):指定最低的日志级别，低于lel的级别将被忽略。debug是最低的内置级别，critical为最高
# Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
# Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)：增加或删除指定的handler
# Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()：可以设置的日志级别

# Handlers
#
# handler对象负责发送相关的信息到指定目的地。可以通过addHandler()方法添加多个多handler
# Handler.setLevel(lel):指定被处理的信息级别，低于lel级别的信息将被忽略
# Handler.setFormatter()：给这个handler选择一个格式
# Handler.addFilter(filt)、Handler.removeFilter(filt)：新增或删除一个filter对象

# Formatters
#
# Formatter对象设置日志信息最后的规则、结构和内容，默认的时间格式为%Y-%m-%d %H:%M:%S，下面是Formatter常用的一些信息


# %(name)s                       Logger的名字
#
# %(levelno)s                    数字形式的日志级别
#
# %(levelname)s                文本形式的日志级别
#
# %(pathname)s                调用日志输出函数的模块的完整路径名，可能没有
#
# %(filename)s                  调用日志输出函数的模块的文件名
#
# %(module)s                    调用日志输出函数的模块名
#
# %(funcName)s                调用日志输出函数的函数名
#
# %(lineno)d                     调用日志输出函数的语句所在的代码行
#
# %(created)f                    当前时间，用UNIX标准的表示时间的浮 点数表示
#
# %(relativeCreated)d        输出日志信息时的，自Logger创建以 来的毫秒数
#
# %(asctime)s                  字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
#
# %(thread)d                   线程ID。可能没有
#
# %(threadName)s           线程名。可能没有
#
# %(process)d                 进程ID。可能没有
#
# %(message)s               用户输出的消息
